#include "Int_W25Q128.h"
#include <stddef.h>

/**
 * @brief 片选控制宏
 */
#define W25Q_CS_LOW(dev)    Dri_SPI_CS_Control((dev)->cs_port, (dev)->cs_pin, 0)
#define W25Q_CS_HIGH(dev)   Dri_SPI_CS_Control((dev)->cs_port, (dev)->cs_pin, 1)

/**
 * @brief 初始化W25Q128设备
 * @param dev 设备结构体指针
 * @param cs_port 片选端口
 * @param cs_pin 片选引脚
 * @return 0-成功, 其他-失败
 */
int W25Q_Init(W25Q_Device_t* dev, GPIO_TypeDef* cs_port, uint16_t cs_pin)
{
    uint32_t jedec_id;
    
    if (dev == NULL) return -1;
    
    /* 设置设备参数 */
    dev->cs_port = cs_port;
    dev->cs_pin = cs_pin;
    dev->capacity = W25Q128_CAPACITY;
    dev->sector_size = W25Q128_SECTOR_SIZE;
    dev->page_size = W25Q128_PAGE_SIZE;
    dev->initialized = 0;
    
    /* 确保片选为高电平 */
    W25Q_CS_HIGH(dev);
    
    /* 读取JEDEC ID验证设备 */
    if (W25Q_ReadJedecID(dev, &jedec_id) != 0)
    {
        return -2;
    }
    
    if (jedec_id != W25Q128_JEDEC_ID)
    {
        return -3; // JEDEC ID不匹配
    }
    
    dev->jedec_id = jedec_id;
    dev->initialized = 1;
    
    return 0;
}

/**
 * @brief 读取JEDEC ID
 * @param dev 设备结构体指针
 * @param jedec_id JEDEC ID指针
 * @return 0-成功, 其他-失败
 */
int W25Q_ReadJedecID(W25Q_Device_t* dev, uint32_t* jedec_id)
{
    uint8_t cmd = W25Q_CMD_JEDEC_ID;
    uint8_t id_data[3];
    
    if (dev == NULL || jedec_id == NULL) return -1;
    
    W25Q_CS_LOW(dev);
    
    /* 发送命令 */
    Dri_SPI_SwapByte(cmd);
    
    /* 读取3字节ID */
    id_data[0] = Dri_SPI_SwapByte(0xFF);
    id_data[1] = Dri_SPI_SwapByte(0xFF);
    id_data[2] = Dri_SPI_SwapByte(0xFF);
    
    W25Q_CS_HIGH(dev);
    
    *jedec_id = (id_data[0] << 16) | (id_data[1] << 8) | id_data[2];
    
    return 0;
}

/**
 * @brief 读取状态寄存器1
 * @param dev 设备结构体指针
 * @return 状态寄存器值
 */
uint8_t W25Q_ReadStatusReg1(W25Q_Device_t* dev)
{
    uint8_t cmd = W25Q_CMD_READ_STATUS_REG1;
    uint8_t status;
    
    if (dev == NULL) return 0xFF;
    
    W25Q_CS_LOW(dev);
    
    Dri_SPI_SwapByte(cmd);
    status = Dri_SPI_SwapByte(0xFF);
    
    W25Q_CS_HIGH(dev);
    
    return status;
}

/**
 * @brief 等待设备空闲
 * @param dev 设备结构体指针
 * @param timeout 超时时间(ms)
 * @return 0-成功, 其他-超时
 */
int W25Q_WaitBusy(W25Q_Device_t* dev, uint32_t timeout)
{
    uint32_t start_time = 0; // 这里应该使用系统时钟
    
    if (dev == NULL) return -1;
    
    while (timeout > 0)
    {
        if ((W25Q_ReadStatusReg1(dev) & W25Q_SR1_BUSY) == 0)
        {
            return 0; // 设备空闲
        }
        
        Delay(1); // 延时1ms
        timeout--;
    }
    
    return -1; // 超时
}

/**
 * @brief 写使能
 * @param dev 设备结构体指针
 */
void W25Q_WriteEnable(W25Q_Device_t* dev)
{
    uint8_t cmd = W25Q_CMD_WRITE_ENABLE;
    
    if (dev == NULL) return;
    
    W25Q_CS_LOW(dev);
    Dri_SPI_SwapByte(cmd);
    W25Q_CS_HIGH(dev);
}

/**
 * @brief 写禁止
 * @param dev 设备结构体指针
 */
void W25Q_WriteDisable(W25Q_Device_t* dev)
{
    uint8_t cmd = W25Q_CMD_WRITE_DISABLE;
    
    if (dev == NULL) return;
    
    W25Q_CS_LOW(dev);
    Dri_SPI_SwapByte(cmd);
    W25Q_CS_HIGH(dev);
}

/**
 * @brief 读取数据
 * @param dev 设备结构体指针
 * @param addr 地址
 * @param buffer 数据缓冲区
 * @param size 数据长度
 * @return 0-成功, 其他-失败
 */
int W25Q_ReadData(W25Q_Device_t* dev, uint32_t addr, uint8_t* buffer, uint32_t size)
{
    uint32_t i;
    
    if (dev == NULL || buffer == NULL || !dev->initialized) return -1;
    if (addr + size > dev->capacity) return -2;
    
    W25Q_CS_LOW(dev);
    
    /* 发送读命令和地址 */
    Dri_SPI_SwapByte(W25Q_CMD_READ_DATA);
    Dri_SPI_SwapByte((addr >> 16) & 0xFF);
    Dri_SPI_SwapByte((addr >> 8) & 0xFF);
    Dri_SPI_SwapByte(addr & 0xFF);
    
    /* 读取数据 */
    for (i = 0; i < size; i++)
    {
        buffer[i] = Dri_SPI_SwapByte(0xFF);
    }
    
    W25Q_CS_HIGH(dev);
    
    return 0;
}

/**
 * @brief 快速读取数据
 * @param dev 设备结构体指针
 * @param addr 地址
 * @param buffer 数据缓冲区
 * @param size 数据长度
 * @return 0-成功, 其他-失败
 */
int W25Q_FastRead(W25Q_Device_t* dev, uint32_t addr, uint8_t* buffer, uint32_t size)
{
    uint32_t i;
    
    if (dev == NULL || buffer == NULL || !dev->initialized) return -1;
    if (addr + size > dev->capacity) return -2;
    
    W25Q_CS_LOW(dev);
    
    /* 发送快速读命令和地址 */
    Dri_SPI_SwapByte(W25Q_CMD_FAST_READ);
    Dri_SPI_SwapByte((addr >> 16) & 0xFF);
    Dri_SPI_SwapByte((addr >> 8) & 0xFF);
    Dri_SPI_SwapByte(addr & 0xFF);
    Dri_SPI_SwapByte(0xFF); // Dummy字节
    
    /* 读取数据 */
    for (i = 0; i < size; i++)
    {
        buffer[i] = Dri_SPI_SwapByte(0xFF);
    }
    
    W25Q_CS_HIGH(dev);
    
    return 0;
}

/**
 * @brief 页编程
 * @param dev 设备结构体指针
 * @param addr 地址
 * @param buffer 数据缓冲区
 * @param size 数据长度(最大256字节)
 * @return 0-成功, 其他-失败
 */
int W25Q_PageProgram(W25Q_Device_t* dev, uint32_t addr, const uint8_t* buffer, uint32_t size)
{
    uint32_t i;
    
    if (dev == NULL || buffer == NULL || !dev->initialized) return -1;
    if (size > dev->page_size) return -2;
    if (addr + size > dev->capacity) return -3;
    
    /* 写使能 */
    W25Q_WriteEnable(dev);
    
    W25Q_CS_LOW(dev);
    
    /* 发送页编程命令和地址 */
    Dri_SPI_SwapByte(W25Q_CMD_PAGE_PROGRAM);
    Dri_SPI_SwapByte((addr >> 16) & 0xFF);
    Dri_SPI_SwapByte((addr >> 8) & 0xFF);
    Dri_SPI_SwapByte(addr & 0xFF);
    
    /* 发送数据 */
    for (i = 0; i < size; i++)
    {
        Dri_SPI_SwapByte(buffer[i]);
    }
    
    W25Q_CS_HIGH(dev);
    
    /* 等待编程完成 */
    return W25Q_WaitBusy(dev, 1000);
}

/**
 * @brief 写入数据(自动处理跨页)
 * @param dev 设备结构体指针
 * @param addr 地址
 * @param buffer 数据缓冲区
 * @param size 数据长度
 * @return 0-成功, 其他-失败
 */
int W25Q_WriteData(W25Q_Device_t* dev, uint32_t addr, const uint8_t* buffer, uint32_t size)
{
    uint32_t page_offset, page_remain, write_size;
    uint32_t current_addr = addr;
    const uint8_t* current_buffer = buffer;
    uint32_t remaining_size = size;
    
    if (dev == NULL || buffer == NULL || !dev->initialized) return -1;
    if (addr + size > dev->capacity) return -2;
    
    while (remaining_size > 0)
    {
        page_offset = current_addr % dev->page_size;
        page_remain = dev->page_size - page_offset;
        write_size = (remaining_size < page_remain) ? remaining_size : page_remain;
        
        if (W25Q_PageProgram(dev, current_addr, current_buffer, write_size) != 0)
        {
            return -3;
        }
        
        current_addr += write_size;
        current_buffer += write_size;
        remaining_size -= write_size;
    }
    
    return 0;
}

/**
 * @brief 扇区擦除(4KB)
 * @param dev 设备结构体指针
 * @param addr 扇区地址
 * @return 0-成功, 其他-失败
 */
int W25Q_SectorErase(W25Q_Device_t* dev, uint32_t addr)
{
    if (dev == NULL || !dev->initialized) return -1;
    if (addr >= dev->capacity) return -2;
    
    /* 地址对齐到扇区边界 */
    addr = (addr / dev->sector_size) * dev->sector_size;
    
    /* 写使能 */
    W25Q_WriteEnable(dev);
    
    W25Q_CS_LOW(dev);
    
    /* 发送扇区擦除命令和地址 */
    Dri_SPI_SwapByte(W25Q_CMD_SECTOR_ERASE);
    Dri_SPI_SwapByte((addr >> 16) & 0xFF);
    Dri_SPI_SwapByte((addr >> 8) & 0xFF);
    Dri_SPI_SwapByte(addr & 0xFF);
    
    W25Q_CS_HIGH(dev);
    
    /* 等待擦除完成 */
    return W25Q_WaitBusy(dev, 5000);
}

/**
 * @brief 块擦除(64KB)
 * @param dev 设备结构体指针
 * @param addr 块地址
 * @return 0-成功, 其他-失败
 */
int W25Q_BlockErase(W25Q_Device_t* dev, uint32_t addr)
{
    if (dev == NULL || !dev->initialized) return -1;
    if (addr >= dev->capacity) return -2;
    
    /* 地址对齐到64KB边界 */
    addr = (addr / (64 * 1024)) * (64 * 1024);
    
    /* 写使能 */
    W25Q_WriteEnable(dev);
    
    W25Q_CS_LOW(dev);
    
    /* 发送块擦除命令和地址 */
    Dri_SPI_SwapByte(W25Q_CMD_BLOCK_ERASE_64K);
    Dri_SPI_SwapByte((addr >> 16) & 0xFF);
    Dri_SPI_SwapByte((addr >> 8) & 0xFF);
    Dri_SPI_SwapByte(addr & 0xFF);
    
    W25Q_CS_HIGH(dev);
    
    /* 等待擦除完成 */
    return W25Q_WaitBusy(dev, 10000);
}

/**
 * @brief 整片擦除
 * @param dev 设备结构体指针
 * @return 0-成功, 其他-失败
 */
int W25Q_ChipErase(W25Q_Device_t* dev)
{
    if (dev == NULL || !dev->initialized) return -1;
    
    /* 写使能 */
    W25Q_WriteEnable(dev);
    
    W25Q_CS_LOW(dev);
    
    /* 发送整片擦除命令 */
    Dri_SPI_SwapByte(W25Q_CMD_CHIP_ERASE);
    
    W25Q_CS_HIGH(dev);
    
    /* 等待擦除完成(可能需要很长时间) */
    return W25Q_WaitBusy(dev, 60000);
}

/* 逻辑卷操作函数 */

/**
 * @brief 初始化逻辑卷
 * @param volume 逻辑卷结构体指针
 * @param dev1 设备1指针
 * @param dev2 设备2指针
 * @return 0-成功, 其他-失败
 */
int W25Q_VolumeInit(W25Q_Volume_t* volume, W25Q_Device_t* dev1, W25Q_Device_t* dev2)
{
    if (volume == NULL) return -1;
    
    volume->device_count = 0;
    volume->total_capacity = 0;
    
    if (dev1 != NULL && dev1->initialized)
    {
        volume->devices[volume->device_count] = dev1;
        volume->total_capacity += dev1->capacity;
        volume->device_count++;
    }
    
    if (dev2 != NULL && dev2->initialized)
    {
        volume->devices[volume->device_count] = dev2;
        volume->total_capacity += dev2->capacity;
        volume->device_count++;
    }
    
    return (volume->device_count > 0) ? 0 : -1;
}

/**
 * @brief 从逻辑卷读取数据
 * @param volume 逻辑卷结构体指针
 * @param addr 逻辑地址
 * @param buffer 数据缓冲区
 * @param size 数据长度
 * @return 0-成功, 其他-失败
 */
int W25Q_VolumeRead(W25Q_Volume_t* volume, uint32_t addr, uint8_t* buffer, uint32_t size)
{
    uint32_t device_capacity;
    uint32_t device_addr;
    uint32_t read_size;
    uint32_t remaining_size = size;
    uint32_t current_addr = addr;
    uint8_t* current_buffer = buffer;
    
    if (volume == NULL || buffer == NULL || volume->device_count == 0) return -1;
    if (addr + size > volume->total_capacity) return -2;
    
    while (remaining_size > 0)
    {
        device_capacity = volume->devices[0]->capacity;
        
        if (current_addr < device_capacity)
        {
            /* 从第一个设备读取 */
            device_addr = current_addr;
            read_size = (remaining_size < (device_capacity - device_addr)) ? 
                       remaining_size : (device_capacity - device_addr);
            
            if (W25Q_FastRead(volume->devices[0], device_addr, current_buffer, read_size) != 0)
            {
                return -3;
            }
        }
        else
        {
            /* 从第二个设备读取 */
            if (volume->device_count < 2) return -4;
            
            device_addr = current_addr - device_capacity;
            read_size = remaining_size;
            
            if (W25Q_FastRead(volume->devices[1], device_addr, current_buffer, read_size) != 0)
            {
                return -5;
            }
        }
        
        current_addr += read_size;
        current_buffer += read_size;
        remaining_size -= read_size;
    }
    
    return 0;
}

/**
 * @brief 向逻辑卷写入数据
 * @param volume 逻辑卷结构体指针
 * @param addr 逻辑地址
 * @param buffer 数据缓冲区
 * @param size 数据长度
 * @return 0-成功, 其他-失败
 */
int W25Q_VolumeWrite(W25Q_Volume_t* volume, uint32_t addr, const uint8_t* buffer, uint32_t size)
{
    uint32_t device_capacity;
    uint32_t device_addr;
    uint32_t write_size;
    uint32_t remaining_size = size;
    uint32_t current_addr = addr;
    const uint8_t* current_buffer = buffer;
    
    if (volume == NULL || buffer == NULL || volume->device_count == 0) return -1;
    if (addr + size > volume->total_capacity) return -2;
    
    while (remaining_size > 0)
    {
        device_capacity = volume->devices[0]->capacity;
        
        if (current_addr < device_capacity)
        {
            /* 写入第一个设备 */
            device_addr = current_addr;
            write_size = (remaining_size < (device_capacity - device_addr)) ? 
                        remaining_size : (device_capacity - device_addr);
            
            if (W25Q_WriteData(volume->devices[0], device_addr, current_buffer, write_size) != 0)
            {
                return -3;
            }
        }
        else
        {
            /* 写入第二个设备 */
            if (volume->device_count < 2) return -4;
            
            device_addr = current_addr - device_capacity;
            write_size = remaining_size;
            
            if (W25Q_WriteData(volume->devices[1], device_addr, current_buffer, write_size) != 0)
            {
                return -5;
            }
        }
        
        current_addr += write_size;
        current_buffer += write_size;
        remaining_size -= write_size;
    }
    
    return 0;
}

/**
 * @brief 逻辑卷扇区擦除
 * @param volume 逻辑卷结构体指针
 * @param addr 逻辑地址
 * @return 0-成功, 其他-失败
 */
int W25Q_VolumeSectorErase(W25Q_Volume_t* volume, uint32_t addr)
{
    uint32_t device_capacity;
    uint32_t device_addr;
    
    if (volume == NULL || volume->device_count == 0) return -1;
    if (addr >= volume->total_capacity) return -2;
    
    device_capacity = volume->devices[0]->capacity;
    
    if (addr < device_capacity)
    {
        /* 擦除第一个设备的扇区 */
        device_addr = addr;
        return W25Q_SectorErase(volume->devices[0], device_addr);
    }
    else
    {
        /* 擦除第二个设备的扇区 */
        if (volume->device_count < 2) return -3;
        
        device_addr = addr - device_capacity;
        return W25Q_SectorErase(volume->devices[1], device_addr);
    }
}
